// Copyright (C) 2005 Taylor L. Riché <riche@cs.utexas.edu>
//  
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software 
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
// 	$Id: DynamicLib.hh 84 2005-08-02 17:20:23Z richetl $	
//

#ifndef DYNAMICLIB_HH
#define DYNAMICLIB_HH

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <dlfcn.h>
#include <stdexcept>
#include <iostream>

namespace dlpp
{

  class DynamicLibException : public std::exception
  {
    std::string error;
  public:
    DynamicLibException(const std::string er) : error(er) {}
    virtual const char *what() const throw() {
      return error.c_str();
    }
    virtual ~DynamicLibException() throw() {}
  };

  template <typename T, typename S>
  class DynamicLib
  {
    void* handle;
  public:
    typedef T (*ret_ptr)(S);
    DynamicLib(std::string filename) throw (DynamicLibException);
    ret_ptr getSymbol(std::string symbol) throw (DynamicLibException);
    virtual ~DynamicLib();
  };

  template <typename T, typename S>
  DynamicLib<T,S>::DynamicLib(std::string filename) throw(DynamicLibException)
  {
    handle = dlopen(filename.c_str(), RTLD_NOW | RTLD_GLOBAL);
    if(handle == NULL) {
      throw DynamicLibException(dlerror());
    }
  }

  template <typename T, typename S>
  DynamicLib<T,S>::~DynamicLib()
  {
    dlclose(handle);
  }

  template <typename T, typename S>
  T (*DynamicLib<T,S>::getSymbol(std::string symbol) throw(DynamicLibException))(S)
  {
    ret_ptr retSym = (ret_ptr)dlsym(handle, symbol.c_str());
    char * error = dlerror();
    if(error != NULL || retSym == NULL) {
      std::string errorString = error;
      throw DynamicLibException(errorString);
    }
    return retSym;
  }


}
#endif // DYNAMICLIB_HH

